# -*- coding: utf-8 -*-
#   文件说明
# @Time    ： 2025/9/2  03:04
# @Auther  ： 徐良
# File     :  aloneWorkAssistant.py
from typing import Optional, List, Any, Tuple
from PySide6.QtCore import Qt, QCoreApplication, QModelIndex, Slot, QDate, QDateTime, QTime, QTimer, QItemSelection, \
    QItemSelectionModel
from PySide6.QtWidgets import QDataWidgetMapper, QHeaderView, QStackedWidget, QWidget
from shiboken6 import Object
import share.globalvar as gol  # 全局变量
from interface_style import apply_styles
from utils.alone.aloneBillFactory import AloneBillFactory
from utils.commonBillClass import CommonBillClass
from baseClass.delegate.dateTimeStringDelegate import DateTimeStringDelegate
from mesParts.lineEdit.f7LineEdits import F7NumberEdit, F7NameEdit, F7SimpleFormEdt
from mesParts.dateTime.dateTimes import DateEdit, DateTimeEdit, TimeEdit
from mesParts.checkBox.checkBoxs import CheckBox
from mesParts.comboBox.comboBoxs import Combox
from PySide6.QtCore import QTimer
from baseClass.record.records import BaseRecord
import logging


class AloneWorkAssistant(AloneBillFactory, CommonBillClass):
    """工作助手主类，负责界面工具栏和菜单栏的动态管理"""

    def __init__(self, parent=None):
        """初始化工作助手"""
        super().__init__(parent)
        self.row = -1
        self.change_row = -1
        self.allow_selection_change = True  # 默认允许行变动
        self.stackedW = "No"
        self.toolbarFlag = '单页面界面'

        self.LINK_TREE = 0  # 0 平面， 1， 树结构
        self.GROUP = 1  # 0: 上级组  1： 明细
        self.GROUP_MANAGE = 0   # 0: 无组关联， 1： 有组管理
        self.TREE_CLICK_FLAG = 0  # 树点击标志，1：是树点击
        self._init_ui_components()
        self._init_work()

    def _init_ui_components(self) -> None:
        """初始化UI相关组件"""
        self.mapper = QDataWidgetMapper()
        self.f_obj_list: List[Optional[QWidget]] = []  # 存储字段控件对象
        self.f_lbl_list: List[Optional[QWidget]] = []  # 存储标签控件对象

    def switch_to_page(self, page_name: str) -> None:
        # 检查 stackedWidget 是否存在
        stacked_widget: Optional[QStackedWidget] = getattr(self, 'stackedWidget', None)
        if not isinstance(stacked_widget, QStackedWidget):
            logging.info(f"[ERROR] stackedWidget not found or invalid in {self.__class__.__name__}")
            return False

        # 获取目标页面对象
        target_page: Optional[QWidget] = getattr(self, page_name, None)
        if not isinstance(target_page, QWidget):
            self.logger.info(f"[ERROR] Page '{page_name}' not found or invalid in {self.__class__.__name__}")
            return False

        # 检查页面是否在 stackedWidget 中
        pages: list[QWidget] = [stacked_widget.widget(i) for i in range(stacked_widget.count())]
        if target_page not in pages:
            self.logger.info(f"[ERROR] Page '{page_name}' is not a member of stackedWidget")
            return False

        # 执行页面切换
        stacked_widget.setCurrentWidget(target_page)
        return True

    # region  【保存】设置
    def _set_save_button_enabled(self, able: bool) -> None:
        """设置【保存】可用"""
        btn = self.get_button('保存')
        if btn is not None:
            btn.setEnabled(able)

    def _init_work(self, fid=-1):
        """
        根据fid，将单据数据读出到编辑面板
        :param fid:
        :return:
        """

        # 设置【保存】不可用
        self._set_save_button_enabled(False)


        self.GROUP_MANAGE = self.m_group_manage

        # 设置【明细】或【上级组】可见
        self.LINK_TREE = self.m_link_tree
        if self.LINK_TREE:
            self._set_classify_button_visible(True)
        else:
            self._set_classify_button_visible(False)

        # 判断是否需要建树
        if self.m_has_tree:
            pass
            # self._build_tree()
            # self.treeWidget.itemDoubleClicked.connect(self.tree_item_db_click)
        else:
            if hasattr(self, 'frame_tree'):
                self.frame_tree.setVisible(False)
    # endregion

    # region 表单创建 读取单表数据


    def read_data_to_form_edit(self, fid: int, row: int=0) -> None:
        # 创建form 表单
        self.create_form(self.gridLayout_form)

        self._set_mapper(row)

        self.switch_to_page('pageEdit')  # 调用baseQWidget的方法，转换页面

        # 设置数据变化的信号连接
        # self._set_head_body_data_on()

        # 设置【保存】可见
        # self._set_save_button_visible(bool(self._save_button_visible))


        # self._read_bill_edit_after()  # 调度，完成单据读入页面后的后续动作

        # 处理单据关闭状态
        # self.handle_bill_closed()
        apply_styles(self)


    # def read_data(self, sql: str = None) -> None:
    #     """
    #     读表数据
    #     :param sql:
    #     :return:
    #     """
    #     if sql is None:
    #         sql = self.m_form_sql
    #
    #     self.form_model = FormModel(work=self, sql=sql)
    #     self.tableView_bill.setModel(self.form_model)
    #
    #     self.tableView_bill.set_column_width_by_number(self.f_column_width_list)
    #     self.tableView_bill.set_visible_column_by_number(self.f_visible_list)
    #
    #     delegate = ColourLessDelegate(**{})
    #     self.tableView_bill.setItemDelegate(delegate)
    #     self._set_label_info()
    #
    #     self.form_model.dataChanged.connect(self.on_model_data_change)
    #
    #     selection_model = self.tableView_bill.selectionModel()
    #     selection_model.currentRowChanged.connect(self.on_row_changed)
    #
    #     self._set_save_button_enabled(False)
    #
    #     # 关键优化：空表时初始化映射器（模型、代理），避免后续新增行时映射器无配置
    #     if self.form_model.rowCount() == 0:
    #         self._clear_mapper_editors()
    #         # 初始化映射器基础配置（模型+代理），后续新增行时只需绑定控件和字段
    #         self.mapper.setModel(self.form_model)
    #         self.mapper.setSubmitPolicy(QDataWidgetMapper.SubmitPolicy.ManualSubmit)
    #         self.mapper.setItemDelegate(DateTimeStringDelegate())
    #     else:
    #         # 非空表正常建立映射（原逻辑保留）
    #         self._set_mapper()
    #         self.row = 0
    #         if self.GROUP_MANAGE:
    #             self._display_group_or_detail()

    # def _clear_mapper_editors(self) -> None:
    #     """
    #     解除映射关系，并清空控件
    #     :return:
    #     """
    #     self.row = -1
    #     self.mapper.clearMapping()
    #     self.allow_selection_change = False
    #     # 遍历所有控件，根据类型清空内容
    #     for visible, obj in zip(self.f_visible_list, self.f_obj_list):
    #         if not visible or obj is None:
    #             continue  # 跳过不可见或空控件
    #
    #         # 根据控件类型调用对应的清空方法
    #         if isinstance(obj, CheckBox):
    #             obj.setChecked(False)  # 复选框取消勾选
    #         elif isinstance(obj, (DateEdit, DateTimeEdit)):
    #             obj.setDate(QDate())  # 日期控件设为空
    #         elif isinstance(obj, TimeEdit):
    #             obj.setTime(QTime())  # 时间控件设为空
    #         elif isinstance(obj, (F7NumberEdit, F7NameEdit, F7SimpleFormEdt)):
    #             obj.clear()  # F7系列输入框清空
    #         elif isinstance(obj, Combox):
    #             obj.setCurrentIndex(-1)  # 下拉框设为无选中
    #         else:
    #             # 通用文本输入控件（如QLineEdit）
    #             if hasattr(obj, "clear"):
    #                 obj.clear()
    #             elif hasattr(obj, "setText"):
    #                 obj.setText("")  # 兜底：设置为空字符串

    def on_model_data_change(self, index) -> None:
        """
        model数据变化响应
        :param index:
        :return:
        """
        self._set_save_button_enabled(True)
        self.allow_selection_change = False

        if index.isValid():
            self.change_row = index.row()


    # endregion


    # region mapper 映射相关的方法
    def _set_mapper(self, row: int) -> None:
        """设置数据映射关系，解决行变化不更新控件的问题"""
        self.mapper.clearMapping()
        self.mapper.setModel(self.form_model)
        # 建议改为ManualSubmit，避免自动提交与行变化冲突
        self.mapper.setSubmitPolicy(QDataWidgetMapper.SubmitPolicy.ManualSubmit)
        self.mapper.setItemDelegate(DateTimeStringDelegate())


        for index, (visible, obj) in enumerate(zip(self.f_visible_list, self.f_obj_list)):
            if not visible or obj is None:
                continue


            if isinstance(obj, CheckBox):
                self.mapper.addMapping(obj, index, b"checked")
                # 绑定带控件和索引参数的提交信号，方便后续过滤
                obj.dataChange.connect(
                    lambda checked, widget=obj, idx=index: self._on_widget_changed(widget, idx)
                )

            elif isinstance(obj, (TimeEdit, DateEdit, DateTimeEdit, F7NumberEdit, F7NameEdit)):
                self.mapper.addMapping(obj, index)
                if hasattr(obj, "timeChangedSignal"):
                    obj.timeChangedSignal.connect(
                        lambda widget=obj, idx=index: self._on_widget_changed(widget, idx)
                    )
                elif hasattr(obj, "dateChangedSignal"):
                    obj.dateChangedSignal.connect(
                        lambda widget=obj, idx=index: self._on_widget_changed(widget, idx)
                    )

            elif isinstance(obj, Combox):
                self.mapper.addMapping(obj, index)
                obj.currentIndexChanged.connect(
                    lambda idx, widget=obj, idx_model=index: self._on_widget_changed(widget, idx_model)
                )

            else:
                self.mapper.addMapping(obj, index)
                # 优先处理自定义dataChange信号
                if hasattr(obj, "dataChange"):
                    obj.dataChange.connect(
                        lambda widget=obj, idx=index: self._on_widget_changed(widget, idx)
                    )
                # 补充标准QLineEdit的textChanged信号（无参数或带文本参数）
                # elif hasattr(obj, "textChanged"):
                #     # 处理带文本参数的textChanged信号（QLineEdit标准信号）
                #     obj.textChanged.connect(
                #         lambda text, widget=obj, idx=index: self._on_widget_changed(widget, idx)
                #     )
                # # 补充其他可能的信号（如editingFinished）
                # elif hasattr(obj, "editingFinished"):
                #     obj.editingFinished.connect(
                #         lambda widget=obj, idx=index: self._on_widget_changed(widget, idx)
                #     )

        self.mapper.setCurrentIndex(row)

    def _on_widget_changed(self, widget, index):
        """仅在数据真实变化时提交，并确保模型发射信号"""

        # 1. 手动校验控件值与模型值是否真的不同（核心）
        current_row = self.mapper.currentIndex()
        model_index = self.form_model.index(current_row, index)
        if not model_index.isValid():
            return

        # 获取控件当前值和模型原始值
        widget_value = self._get_widget_value(widget)
        model_value = self.form_model.data(model_index)

        # 3. 只有值真正变化时才提交
        if self._values_are_equal(widget_value, model_value):
            return  # 值未变，不提交

        self.mapper.submit()

    # # 补充行变化处理函数的优化（关键）
    # def on_row_changed(self, current, previous):
    #     """行变化时，临时屏蔽控件信号，避免触发提交"""
    #     if not current.isValid():
    #         self._clear_mapper_editors()
    #         return
    #
    #     # 如果数据已变化，则不允许行变动
    #     if not self.allow_selection_change:
    #         self.row = self.change_row
    #         # 阻断控件信号（可选，更彻底）
    #         self._block_widget_signals(True)
    #         self.mapper.setCurrentIndex(self.row)
    #         self._block_widget_signals(False)
    #
    #         self.status_bar_show_message('数据发生变化, 请点击【保存】，或点击【刷新】放弃修改')
    #
    #     else:
    #          # 阻断控件信号（可选，更彻底）
    #         self._block_widget_signals(True)
    #         # 更新映射器到新行，此时控件会被刷新但不触发提交
    #         self.row = current.row()
    #         self.mapper.setCurrentIndex(self.row)
    #         # 恢复信号和提交允许状态
    #         self._block_widget_signals(False)
    #         self.allow_selection_change = True
    #         self.change_row = -1
    #
    #         if self.GROUP_MANAGE:
    #             self._display_group_or_detail()
    #
    # def _block_widget_signals(self, block):
    #     """批量阻断/恢复控件信号"""
    #     for visible, obj in zip(self.f_visible_list, self.f_obj_list):
    #         if visible and obj is not None and hasattr(obj, "blockSignals"):
    #             obj.blockSignals(block)

    @staticmethod
    def _get_widget_value(widget):
        """
        根据控件类型获取对应的值
        需覆盖所有可能的控件类型（根据你的实际控件扩展）
        """
        if isinstance(widget, CheckBox):
            # 复选框返回布尔值（是否勾选）
            return widget.isChecked()
        elif isinstance(widget, (TimeEdit, DateEdit, DateTimeEdit)):
            # 日期时间控件返回文本（与模型存储格式保持一致）
            return widget.text()
        elif isinstance(widget, Combox):
            # 下拉框返回选中的索引或文本（根据你的模型存储方式选择）
            return widget.currentIndex()  # 或 widget.currentText()
        elif isinstance(widget, (F7NumberEdit, F7NameEdit, F7SimpleFormEdt)):
            # F7系列控件返回文本值
            return widget.text().strip()
        elif hasattr(widget, "text"):
            # 通用文本控件（如QLineEdit）返回文本
            return widget.text().strip()
        else:
            # 未知控件类型，返回空字符串或记录日志
            logging.warning(f"未处理的控件类型：{type(widget)}")
            return ""

    @staticmethod
    def _values_are_equal(val1, val2):
        """
        判断两个值是否相等（处理类型和格式差异）
        """
        # 统一转为字符串比较，避免类型差异导致的误判
        return str(val1) == str(val2)

    # endregion


    # region 设置【保存】、【分类】命令可用、可见。 异步、回调
    @staticmethod
    def get_button_async(btnName: str, callback, max_retries=5, delay=300):
        """异步获取按钮对象
        Args:
            btnName: 按钮名称
            callback: 找到按钮后的回调函数
            max_retries: 最大重试次数
            delay: 每次重试的延迟时间(毫秒)
        """

        def try_get(attempt=0):
            # 首次次尝试查找按钮

            # 1. 获取按钮列表
            action_list = gol.get_value('actionList')

            # 2. 如果列表存在，尝试查找按钮
            if action_list is not None:
                button = next((obj for obj in action_list if obj.text() == btnName), None)
                if button is not None:
                    # 成功找到按钮
                    callback(button)  # 找到按钮，调用回调函数
                    return

            # 3. 如果没找到，判断是否继续重试
            if attempt < max_retries - 1:
                # 未找到按钮，延时300s后重试...
                # 设置定时器，延时后再次尝试
                QTimer.singleShot(delay, lambda: try_get(attempt + 1))
            else:
                # 已达到最大重试次数,停止查找
                callback(None)  # 最终没找到，回调None

        # 开始第一次尝试
        try_get()

    def _set_classify_button_visible(self, visible: bool) -> None:
        """
        设置工具栏【分类】命令按钮可见
        """

        def on_button_found(obj):
            """找到按钮后的回调函数"""
            if obj is not None:
                obj.setVisible(visible)
            else:
                print(f"警告：未找到【明细】或【上级组】按钮，已尝试多次")
                pass

        # 开始异步查找按钮
        if self.GROUP:
            self.get_button_async('上级组', on_button_found)
        else:
            self.get_button_async('明细', on_button_found)

    # endregion


    # region 过滤返回, 退回
    # def on_query_action(self, condition: str) -> None:
    #     """
    #     执行过滤返回
    #     :param condition:
    #     :return:
    #     """
    #     sql = self.m_form_sql
    #     sql = SqlFunction.add_where_str(sql, condition)
    #     self.read_data(sql)
    #

    def _page_go_back(self):
        """
        返回浏览页面  重新设置工具栏上的命令
        :return:
        """
        self.switch_to_page('pageBrowse')           # 调用baseQWidget中的方法
        # 清除工具栏上的action   此状态为browser
        # self._clean_toolbar_menubar()
        # 重设工具
        # self._reset_toolbar_menubar('browse')  # 设置到browse类型的面板

        # self.m_save_type = 1  # 置维护记录标志

        # self._save_button_visible = 1
        # self.goBackSignal.emit('ok')          # 发出‘退回’完成信号

    def transfer_go_back(self) -> None:
        """单据编辑界面返回单据浏览界面"""
        # 检查保存命令是否可用
        # if not self._check_save_btn_is_enabled('单据数据已变化，确认退回吗'):
        #     return
        self._page_go_back()

    # endregion


    # # region 一般通用方法
    # def _get_enabled_editor_obj(self) -> Optional[Object]:
    #     """
    #     获取第1个可编辑的控件
    #     :return:
    #     """
    #     ret = None
    #     for obj in self.f_obj_list:
    #         if obj is not None and obj.isEnabled():
    #             ret = obj
    #             break
    #     return ret
    #
    # @staticmethod
    # def _set_save_button_enabled(visible: bool = True) -> None:
    #     """
    #     设置工具栏【保存】命令按钮可用
    #     :param visible:
    #     :return:
    #     """
    #     obj = BaseWindow.get_button('保存')
    #     if obj is not None:
    #         obj.setEnabled(visible)
    #
    # @staticmethod
    # def status_bar_show_message(info: str) -> None:
    #     """
    #     状态栏显示信息
    #     :param info:
    #     :return:
    #     """
    #     statusBar = gol.get_value('statusBar')
    #     statusBar.clearMessage()
    #     statusBar.showMessage(info, 6000)
    #
    # @staticmethod
    # def check_save_is_valid() -> bool:
    #     """
    #     检查【保存】命令是否有效
    #     :return:
    #     """
    #     obj = BaseWindow.get_button('保存')
    #     if obj is None:
    #         return False
    #     elif obj.isEnabled():
    #         return True
    #     else:
    #         return False
    #
    # def _set_label_info(self) -> None:
    #     """
    #     设置当前记录数显示
    #     :return:
    #     """
    #     rec_count = self.form_model.rowCount()
    #     self.lbl_info.setText(f"记录数：{rec_count}")
    #
    # def _build_tree(self) -> None:
    #     """
    #     初始化面板
    #     :return:
    #     """
    #     # 建树
    #     self.treeWidget.clear()
    #     self.treeWidget.add_first_level(self.m_tree_sql)
    #     self.treeWidget.header().setSectionResizeMode(QHeaderView.ResizeMode.ResizeToContents)
    #
    # # endregion


    # region 新记录模式、记录行变化
    def _set_new_record_editor_pattern(self) -> None:
        """
        设置新记录编辑模式
        :param index:
        :return:
        """
        first_editor = self._get_enabled_editor_obj()
        first_editor.setFocus()
        self._set_save_button_enabled(True)
        self.allow_selection_change = False

    # endregion


    # # region 新增 保存 刷新 复制
    # def save_record(self) -> None:
    #     """
    #     记录保存
    #     :return:
    #     """
    #
    #     self.mapper.submit()
    #     # 检查单据表头必录项
    #     if not self._check_must_be_record():
    #         return
    #
    #     # 检查f7控件的隐藏错误的可能
    #     if not self._check_form_f7_correct():
    #         return
    #
    #     if self.row >= 0:
    #         record = self.form_model.record(self.row)
    #
    #         save_action = SaveRecordAction()
    #         reply, fid, exe_type = save_action.saveRecord(
    #             formTable=self.m_form_table,
    #             form_record=record,
    #             f_joinList=self.f_join_sql_list,
    #             f_typeList=self.f_data_type_list,
    #             f_fieldList=self.f_field_list,
    #             link_field=self.m_link_field,
    #             f_detail=self.GROUP,
    #             group_manage=self.GROUP_MANAGE
    #         )
    #         if reply:
    #             self._set_save_button_enabled(False)
    #             self.allow_selection_change = True
    #             self.read_data()
    #             # 定位fid
    #             self._locate_fid(fid)
    #             if self.LINK_TREE:
    #                 self._build_tree()
    #
    #
    # def add_new_record(self) -> None:
    #     """
    #     新增记录
    #     :return:
    #     """
    #
    #     if self.check_save_is_valid():
    #         self.status_bar_show_message('新增记录，或数据发生变动，请保存，或点击【刷新】重新读取数据')
    #         return
    #
    #     # 1. 记录当前模型行数，确定新增行的索引
    #     current_row_count = self.form_model.rowCount()
    #     self.row = current_row_count  # 新增行索引 = 当前行数（空表时为0）
    #
    #     # 2. 插入新行（空表时插入第一行）
    #     self.form_model.insertRows(self.row, 1)
    #
    #     # 3. 关键：无论是否空表，新增行后重新建立映射关系
    #     # （空表时原映射已被清空，必须重新执行 _set_mapper 绑定控件与字段）
    #     self._set_mapper()
    #
    #     # 4. 同步映射器到新增行（确保映射器指向正确行）
    #     self.mapper.setCurrentIndex(self.row)
    #
    #     # 5. 处理组管理逻辑（原逻辑保留，确保FDetail字段正确赋值）
    #     if self.GROUP_MANAGE:
    #         i_col = self.get_f_field_column('FDetail')
    #         index = self.form_model.index(self.row, i_col)
    #         if self.GROUP:
    #             self.form_model.setData(index, 1)
    #
    #         else:
    #             self.form_model.setData(index, 0)
    #
    #         self._display_group_or_detail()
    #
    #     # 6. 空表新增第一行的特殊处理（完善数据初始化和视图同步）
    #     if current_row_count == 0:  # 仅空表时执行
    #         # 初始化第一行默认数据（根据实际业务调整字段索引和值）
    #         # 注意：索引需与 self.f_field_list 中的字段顺序对应
    #         index_code = self.form_model.index(self.row, 1)  # 假设第2列是编码字段
    #         index_name = self.form_model.index(self.row, 2)  # 假设第3列是名称字段
    #         self.form_model.setData(index_code, '00')  # 编码默认值
    #         self.form_model.setData(index_name, '空表首记录')  # 名称默认值
    #
    #         # 提交初始数据（确保模型正确记录值）
    #         self.mapper.submit()
    #
    #         # 同步表格视图选择（让表格高亮显示新增行）
    #         index_first_col = self.form_model.index(self.row, 0)  # 第一列索引
    #         self.tableView_bill.setCurrentIndex(index_first_col)
    #
    #         # 强制刷新视图（避免UI显示延迟）
    #         self.tableView_bill.viewport().update()
    #     else:
    #         # 非空表新增：同步表格视图选择
    #         index_first_col = self.form_model.index(self.row, 0)
    #         self.tableView_bill.setCurrentIndex(index_first_col)
    #
    #     # 7. 进入新记录编辑模式（聚焦第一个可编辑控件、启用保存按钮）
    #     self._set_new_record_editor_pattern()
    #
    #
    # def refresh_data(self) -> None:
    #     """
    #     刷新数据
    #     :return:
    #     """
    #     self.read_data()
    #     self.allow_selection_change = True
    #
    # def copy_record(self, record: BaseRecord) -> None:
    #     """
    #     复制记录
    #     :param record:
    #     :return:
    #     """
    #     self.row = self.form_model.rowCount()
    #     self.form_model.insertRows(self.row, 1)
    #
    #     for field in self.f_field_list:
    #         v = record.value(field)
    #         if v is not None:
    #             i_col = self.get_f_field_column(field)
    #             index = self.form_model.index(self.row, i_col)
    #             self.form_model.setData(index, v)
    #
    #     self.mapper.setCurrentIndex(self.row)
    #     self._set_new_record_editor_pattern()
    #
    # # endregion


    # region 分类（分组）
    def _get_lbl_ojb_list(self) -> List[Tuple[Any, Any]]:
        lbl_obj_list = []

        for group, lbl, obj in zip(self.f_group_list,
                                   self.f_lbl_list,
                                   self.f_obj_list
                                   ):
            if group == 0 and obj is not None:
                tup = (lbl, obj,)
                lbl_obj_list.append(tup)
        return lbl_obj_list

    def _set_group_pattern(self, obj_list: List[Tuple[Any, Any]]) -> None:
        """
        甚至上级组模式
        :return:
        """
        for (lbl, obj) in obj_list:
            lbl.setVisible(False)
            obj.setVisible(False)

        # 设置上级组、明细命令，设置self.GROUP
        self.GROUP = 0


    def _set_detail_pattern(self, obj_list: List[Tuple[Any, Any]]) -> None:
        """
        设置明细模式
        :return:
        """
        for (lbl, obj) in obj_list:
            lbl.setVisible(True)
            obj.setVisible(True)

        # 设置上级组、明细命令，设置self.GROUP
        self.GROUP = 1


    def _set_classify_button_name(self, group: int) -> None:
        """
        设置组明细分类命令的显示
        :param group:
        :return:
        """
        def change_button_name(obj: Any) -> None:
            if obj is not None:
                if group == 1:
                    obj.setText('明细')
                    obj.setToolTip('明细')
                else:
                    obj.setText('上级组')
                    obj.setToolTip('上级组')

        if group == 1:
            self.get_button_async('上级组', change_button_name)
        else:
            self.get_button_async('明细', change_button_name)


    def _set_classify_pattern(self) -> None:
        """
        设置编辑分类模式
        :return:
        """
        obj_list = self._get_lbl_ojb_list()
        if self.GROUP:
            self._set_group_pattern(obj_list)
        else:
            self._set_detail_pattern(obj_list)

    # def handle_classify(self):
    #     """
    #     处理【上级组】、【明细】点击
    #     :return:
    #     """
    #
    #     try:
    #         # 获取按钮对象（优先尝试获取"蓝字"按钮）
    #         button = BaseWindow.get_button('明细') or BaseWindow.get_button('上级组')
    #
    #         if not button:
    #             logging.warning("未找到明细-上机组切换按钮")
    #             return
    #
    #         # 确定当前状态和要切换的状态
    #         current_text = button.text()
    #
    #         if current_text not in ('明细', '上级组'):
    #             logging.error(f"无效的按钮文本: {current_text}")
    #             return
    #
    #         # 切换状态
    #         new_text = '上级组' if current_text == '明细' else '明细'
    #         self.GROUP = 1 if new_text == '明细' else 0
    #
    #         # 修正明细字段
    #         i_col = self.get_f_field_column('FDetail')
    #         index = self.form_model.index(self.row, i_col)
    #         if self.GROUP:
    #             self.form_model.setData(index, 1)
    #         else:
    #             self.form_model.setData(index, 0)
    #
    #         # 更新UI
    #         button.setText(new_text)
    #         button.setToolTip(new_text)
    #
    #         self._set_save_button_enabled(True)
    #         self.allow_selection_change = False
    #         obj_list = self._get_lbl_ojb_list()
    #         if self.GROUP == 0:
    #             self._clear_detail_data()
    #             self._set_group_pattern(obj_list)
    #         else:
    #             self._set_detail_pattern(obj_list)
    #
    #     except Exception as e:
    #         logging.error(f"明细-上机组切换按钮: {str(e)}", exc_info=True)
    #
    # def _clear_detail_data(self) -> None:
    #     """
    #     清空除FGroup=1之外的数据，包括控件和model
    #     :return:
    #     """
    #     for visible, obj, fgroup in zip(self.f_visible_list, self.f_obj_list, self.f_group_list):
    #         if not visible or obj is None:
    #             continue  # 跳过不可见或空控件
    #
    #         if fgroup:
    #             continue    # 跳过组字段
    #
    #         # 根据控件类型调用对应的清空方法
    #         if isinstance(obj, CheckBox):
    #             obj.setChecked(False)  # 复选框取消勾选
    #         elif isinstance(obj, (DateEdit, DateTimeEdit)):
    #             obj.setDate(QDate())  # 日期控件设为空
    #         elif isinstance(obj, TimeEdit):
    #             obj.setTime(QTime())  # 时间控件设为空
    #         elif isinstance(obj, (F7NumberEdit, F7NameEdit, F7SimpleFormEdt)):
    #             obj.clear()  # F7系列输入框清空
    #         elif isinstance(obj, Combox):
    #             obj.setCurrentIndex(-1)  # 下拉框设为无选中
    #         else:
    #             # 通用文本输入控件（如QLineEdit）
    #             if hasattr(obj, "clear"):
    #                 obj.clear()
    #             elif hasattr(obj, "setText"):
    #                 obj.setText("")  # 兜底：设置为空字符串

    def _display_group_or_detail(self):
        """
        按组或明细要求显示
        :return:
        """
        obj_list = self._get_lbl_ojb_list()
        detail = self.form_model.record(self.row).value('FDetail')
        if detail:
            self._set_detail_pattern(obj_list)
        else:
            self._set_group_pattern(obj_list)

        self._set_classify_button_name(self.GROUP)

    # endregion


    # # region 必录项检查
    # def _get_form_f7_obj(self) -> List[Any]:
    #     """
    #     取表头f7控件，且是可编辑的
    #     :return:
    #     """
    #     obj_list = []
    #     for isedit, obj in zip(self.f_edit_list, self.f_obj_list):
    #         if isedit:
    #             if isinstance(obj, (F7NumberEdit, F7NameEdit)):
    #                 obj_list.append(obj)
    #     return obj_list
    #
    # def _check_must_be_record(self) -> bool:
    #     """
    #     检查表头必录项
    #     :return:
    #     """
    #     must_flag = True
    #     must_field_list = self._get_f_must_input_field()
    #
    #     for must_field in must_field_list:
    #         label, input_obj = self._get_must_input_lbl_obj(must_field)
    #
    #         if input_obj is None or not input_obj.isVisible:
    #             continue
    #
    #         if isinstance(input_obj, Combox):
    #             if input_obj.currentText() == '':
    #                 label.setMust(1)
    #                 must_flag = False
    #         elif input_obj.text() == '':
    #             label.setMust(1)
    #             self.status_bar_show_message('请输入表头必录项')
    #             must_flag = False
    #         else:
    #             label.setMust(0)
    #
    #     return must_flag
    #
    # def _check_form_f7_correct(self) -> bool:
    #     """
    #     检查表f7控件正确性
    #     :return:
    #     """
    #     f7_list = self._get_form_f7_obj()
    #     ret = True
    #     for obj in f7_list:
    #         if obj.correct == 2:
    #             label = self._get_f_label(obj.objectName())
    #             if label is not None:
    #                 label.addError()
    #             ret = False
    #     return ret
    # # endregion
    #
    #
    # # region 其它方法, 树点击
    # def tree_item_db_click(self, it, col):
    #     if not self.allow_selection_change:
    #         self.status_bar_show_message('新增记录，或数据发生变动，请保存，或点击【刷新】重新读取数据')
    #         return
    #
    #     swo = SqlFunction.get_swo(self.m_form_sql)
    #     s = swo['s']
    #     number = it.text(0)
    #     i_len = len(number)
    #     link_number = self.m_link_field
    #     where = f" left({link_number},{i_len})='{number}' order by {link_number}"
    #     sql = SqlFunction.add_where_str(s, where)
    #
    #     self.TREE_CLICK_FLAG = 1
    #     self.read_data(sql)
    #     # 存在组和明细切换的情况
    #     self._set_save_button_enabled(False)
    #     self.allow_selection_change = True
    #
    # def _locate_fid(self, fid: int) -> None:
    #     """
    #     定位model的fid位置
    #     :param fid:
    #     :return:
    #     """
    #     i_row = 0
    #     for row in range(0, self.form_model.rowCount()):
    #         if self.form_model.record(row).value('FId') == fid:
    #             i_row = row
    #             break
    #
    #     self._block_widget_signals(True)
    #     self.change_row = -1
    #     self.row = i_row
    #     # 更新映射器到新行，此时控件会被刷新但不触发提交
    #     self.mapper.setCurrentIndex(self.row)
    #     if self.GROUP_MANAGE:
    #         self._display_group_or_detail()
    #     index = self.form_model.index(self.row, 0)
    #     self.tableView_bill.setCurrentIndex(index)
    #     # 恢复信号和提交允许状态
    #     self._block_widget_signals(False)
    #     self.allow_selection_change = True
    #     self._set_save_button_enabled(False)
    #
    # # endregion
